import java.sql.SQLException;
import java.util.Vector;

/**
 *
 * @author Infinity
 */
public class Process 
{
    Vector<Node> newlist = new Vector<Node>();
    int x = 0;
    String className;
    String access;
    Database database;
    String methodFieldList = "";
    String methodID = "";
    Field parameterArray[] = new Field[20];
    Field globalvar[] = new Field[50];
    Field innervar[] = new Field[50];
    int fieldCounter = 0;
    int globalCounter = 0;
    int innerCounter = 0;
    boolean Consflag = true;
    private boolean interfc = false;
    
    /**
     * The constructor that allows connection to infinitysolutions database
     * @param list Vector<Node>. The list containing the file
     */    
    public Process(Vector<Node> list) throws SQLException, InstantiationException, IllegalAccessException, ClassNotFoundException 
    {
        database = new Database();
        Consflag = true;
        database.connect();
        newlist = list;
        className = newlist.firstElement().getName();
        if(newlist.get(1).getName().equals("interface"))
        {
            interfc = true;
        }
        int classLineNum = newlist.firstElement().getLineNum();
        while(x < newlist.size() )
        {
            if(newlist.get(x).getName().equals("CONSTRUCTOR_DECL"))
            {
                ConstructorMethod();
                Consflag = true;
            }
            if(newlist.get(x).getName().equals("VOID_METHOD_DECL"))
            {
                method();
            }
            if(newlist.get(x).getName().equals("IMPLEMENTS_CLAUSE") || (x > 0 && newlist.get(x-1).getName().equals("IMPLEMENTS_CLAUSE")))
            {
                implementsMethod();
            }         
            if(newlist.get(x).getName().equals("FUNCTION_METHOD_DECL"))
            {
                methodReturn();
            }
            if(newlist.get(x).getName().equals("VAR_DECLARATOR"))
            {
                methodVar();
            }
            if(newlist.get(x).getName().equals("EXTENDS_CLAUSE") || (x > 0 && newlist.get(x-1).getName().equals("EXTENDS_CLAUSE")))
            {
                extendsMethod();
            }
            if(newlist.get(x).getName().equals("MODIFIER_LIST"))
            {
                 if(interfc == false)
                {
                    access = newlist.get(x+1).getName();
                }
                else
                {
                    access = newlist.get(1).getName();
                }
                getImport(x+2);
                database.insertClass(className,access,classLineNum); 
                x++;
            }
            if(Consflag == true)
            {
                Consflag = false;
            }
            else
                x++;
        }
        int c = 0;   
        while(c < globalCounter)
        {
            int fieldID = database.insertField(globalvar[c].getFieldName(), globalvar[c].getAccmode(), globalvar[c].getFieldType(), "0", className, globalvar[c].getArray(),globalvar[c].getVariableScope(),globalvar[c].getLineNum());
            c++;
        } 
        globalCounter = 0;
        database.disconnect();
    }

    Process() 
    {
    }

    /**
     * The method method processes the method which does not return any value(void)
     */    
    public void method() 
    {
        String methodName = newlist.get(x - 1).getName();
        int lineNum = newlist.get(x - 1).getLineNum();
        boolean flag = true;
        while(flag == true)
        {
            if(newlist.get(x).getName().equals("VAR_DECLARATOR"))
            {
                innerVar();
            }
            if(newlist.get(x).getName().equals("FORMAL_PARAM_STD_DECL"))
            {
                parameter();
            }
            if(newlist.get(x).getName().equals("MODIFIER_LIST"))
            {
                flag = false;
            }
            x++;
            if(newlist.get(x).getName().equals("VOID_METHOD_DECL"))
            {
                method();
            }
            if(newlist.get(x).getName().equals("FUNCTION_METHOD_DECL"))
            {
                methodReturn();
            }
        }
        declaration();
        String modifier = newlist.get(x).getName();
        if(!modifier.equals("public") && !modifier.equals("private") && !modifier.equals("protected"))
        {
            modifier = "public";
        }
        int methodID = database.insertMethod(methodName, "void", modifier, className, methodFieldList,lineNum);            
        int c = 0;            
        while(c < fieldCounter)
        {
            int fieldID = database.insertField(parameterArray[c].getFieldName(), parameterArray[c].getAccmode(), parameterArray[c].getFieldType(), methodID+"", className, parameterArray[c].getArray(),parameterArray[c].getVariableScope(),parameterArray[c].getLineNum());
            c++;
            methodFieldList = methodFieldList + fieldID + " " ;
        }
        database.updatemethodFieldList(methodFieldList,methodID);
        methodFieldList = "";
        fieldCounter = 0;
        c = 0;
        while(c < innerCounter)
        {
            int fieldID = database.insertField(innervar[c].getFieldName(), innervar[c].getAccmode(), innervar[c].getFieldType(), methodID+"", className, innervar[c].getArray(),innervar[c].getVariableScope(),innervar[c].getLineNum());
            c++;
        }
        innerCounter = 0;
    }
    
    /**
     * The methodReturn method processes the method which have a return type
     */
    public void methodReturn() 
    {
        methodFieldList = "";
        String methodName = newlist.get(x - 1).getName();
        int lineNum = newlist.get(x - 1).getLineNum();
        String returnType= "";
        boolean flag = true;
        while(flag == true)
        {
            if(newlist.get(x).getName().equals("VAR_DECLARATOR"))
            {
                innerVar();
            }
            if(newlist.get(x).getName().equals("FORMAL_PARAM_STD_DECL"))
            {
                parameter();
            }
            if(newlist.get(x).getName().equals("MODIFIER_LIST"))
            {
                flag = false;
            }
            if(newlist.get(x).getName().equals("TYPE"))
            {
                if(newlist.get(x+1).getName().equals("QUALIFIED_TYPE_IDENT"))
                {
                    if(newlist.get(x+3).getName().equals("MODIFIER_LIST") ||  newlist.get(x+3).getName().equals("LOCAL_MODIFIER_LIST"))
                        returnType = newlist.get(x+2).getName();
                    else
                        returnType = newlist.get(x+3).getName();
                }
                else
                    returnType = newlist.get(x+1).getName();
            }
            x++;
        }

        declaration();
        String modifier = newlist.get(x).getName();
        int methodID = database.insertMethod(methodName, returnType, modifier, className, methodFieldList,lineNum);
        int c = 0;
        while(c < fieldCounter)
        {
            int fieldID = database.insertField(parameterArray[c].getFieldName(), parameterArray[c].getAccmode(), parameterArray[c].getFieldType(), methodID+"", className, parameterArray[c].getArray(),parameterArray[c].getVariableScope(),parameterArray[c].getLineNum());
            c++;
            methodFieldList = methodFieldList + fieldID + " " ;
        }
        database.updatemethodFieldList(methodFieldList,methodID);
        methodFieldList = "";
        fieldCounter = 0;
        c = 0;
        while(c < innerCounter)
        {
            int fieldID = database.insertField(innervar[c].getFieldName(), innervar[c].getAccmode(), innervar[c].getFieldType(), methodID+"", className, innervar[c].getArray(),innervar[c].getVariableScope(),innervar[c].getLineNum());
            c++;
        }
        innerCounter = 0;
    }
    
    /**
     * The methodVar method processes the variables of a method only
     */
    public void methodVar() 
    {
        String varName="";
        int lineNum = -1;
        String type = "";
        boolean array = false;
        boolean flag = true;
        while(flag == true)
        {
            if(newlist.get(x).getName().equals("MODIFIER_LIST"))
            {
                type = newlist.get(x - 1).getName();
                flag = false;
            }
            if(newlist.get(x).getName().equals("ARRAY_DECLARATOR"))
            {
                array = true;                    
            }
            if(newlist.get(x).getName().equals("FUNCTION_METHOD_DECL"))
            {
                while(!newlist.get(x).getName().equals("MODIFIER_LIST"))
                {
                    x++;
                }
                x++;
            }
            if(newlist.get(x).getName().equals("TYPE"))
            {
                if(newlist.get(x-1).getName().equals(">"))
                {

                }
                else
                {
                    varName = newlist.get(x-1).getName();
                    lineNum = newlist.get(x-1).getLineNum();
                }
            }                
            x++;
        }
        String modifier;
        declaration();
        if(newlist.get(x).getName().equals("public") || newlist.get(x).getName().equals("private") || newlist.get(x).getName().equals("protected"))
            modifier = newlist.get(x).getName();                
        else
            modifier = "private";
        globalvar[globalCounter] = new Field();
        globalvar[globalCounter].setFieldName(varName);
        globalvar[globalCounter].setAccmode(modifier);
        globalvar[globalCounter].setFieldType(type);
        globalvar[globalCounter].setArray(array);
        globalvar[globalCounter].setVariableScope("global");
        globalvar[globalCounter].setLineNum(lineNum);
        globalCounter++;
    }

    /**
     * The implementsMethod method processes the implements of a class
     */   
    public void implementsMethod()
    {
        boolean dec = false;
        if(!newlist.get(x).getName().equals("IMPLEMENTS_CLAUSE"))
        {
            dec = true;
            x--;
        }
        String implemented = newlist.get(x+3).getName();
        database.insertExtends_Implements(className,implemented,"implements");
        while(newlist.get(x+4).getName().equals("TYPE"))
        {
            x+=3;
            implemented = newlist.get(x+3).getName();
            database.insertExtends_Implements(className,implemented,"implements");
        }
        if(dec == true)
        {
            x+=2;
        }
        else
        {
            x++;
        }
    }
    
    /**
     * The extendsMethod method processes the extends of a class
     */       
    public void extendsMethod()
    {
        String extended = newlist.get(x+3).getName();
        database.insertExtends_Implements(className,extended,"extends");
        x+=2;
    }
    
    /**
     * The declaration method increaments the index counter if there is static or final on a var declaration
     */     
    public void declaration()
    {
        if(newlist.get(x).getName().equals("static"))
        {
            x++;
        }
        if(newlist.get(x).getName().equals("final"))
        {
            x++;
        }
        if(newlist.get(x).getName().equals("static"))
        {
            x++;
        }
    }

    /**
     * The innerVar method,processes the method variables
     */     
    public void innerVar()
    {
        String varName="";
        int lineNum = -1;
        String type = "";
        boolean array = false;
        boolean flag = true;
        while(flag == true)
        {
            if(newlist.get(x).getName().equals("LOCAL_MODIFIER_LIST"))
            {
                type = newlist.get(x - 1).getName();
                flag = false;
            }
            if(newlist.get(x).getName().equals("ARRAY_DECLARATOR"))
            {
                array = true;
            }
            if(newlist.get(x).getName().equals("FUNCTION_METHOD_DECL"))
            {
                while(!newlist.get(x).getName().equals("LOCAL_MODIFIER_LIST"))
                {
                    x++;
                }
                x++;
            }
            if(newlist.get(x).getName().equals("TYPE"))
            {
                if(newlist.get(x-1).getName().equals(">"))
                {

                }
                else
                {
                    varName = newlist.get(x-1).getName();
                    lineNum = newlist.get(x - 1).getLineNum();
                }
            }                

            x++;
        }
        String modifier;
        declaration();
        if(newlist.get(x).getName().equals("public") || newlist.get(x).getName().equals("private") || newlist.get(x).getName().equals("protected"))
            modifier = newlist.get(x).getName();                
        else
            modifier = "noAccess";
        innervar[innerCounter] = new Field();
        innervar[innerCounter].setFieldName(varName);
        innervar[innerCounter].setAccmode(modifier);
        innervar[innerCounter].setFieldType(type);
        innervar[innerCounter].setArray(array);
        innervar[innerCounter].setVariableScope("methodVariable");
        innervar[innerCounter].setLineNum(lineNum);
        innerCounter++;
    }

    /**
     * The parameter method,processes the parameters of a method
     */     
    public void parameter() 
    {
        String varName="";
        int lineNum = -1;
        String type = "";
        boolean array = false;
        boolean flag = true;
        while(flag == true)
        {
            if(newlist.get(x).getName().equals("LOCAL_MODIFIER_LIST"))
            {
                type = newlist.get(x - 1).getName();
                flag = false;                    
            }
            if(newlist.get(x).getName().equals("ARRAY_DECLARATOR"))
            {
                array = true;                    
            }
            if(newlist.get(x).getName().equals("FUNCTION_METHOD_DECL"))
            {
                while(!newlist.get(x).getName().equals("LOCAL_MODIFIER_LIST"))
                {
                    x++;
                }
                x++;
            }
            if(newlist.get(x).getName().equals("TYPE"))
            {
                if(!newlist.get(x-1).getName().equals(">"))
                {
                    varName = newlist.get(x-1).getName();
                    lineNum = newlist.get(x-1).getLineNum();
                }
            }                
            x++;
        }
        String modifier;
        declaration();
        if(newlist.get(x).getName().equals("public") || newlist.get(x).getName().equals("private") || newlist.get(x).getName().equals("protected"))
            modifier = newlist.get(x).getName();                
        else
            modifier = "noAccess";
        parameterArray[fieldCounter] = new Field();
        parameterArray[fieldCounter].setFieldName(varName);
        parameterArray[fieldCounter].setAccmode(modifier);
        parameterArray[fieldCounter].setFieldType(type);
        parameterArray[fieldCounter].setArray(array);
        parameterArray[fieldCounter].setVariableScope("parameter");
        parameterArray[fieldCounter].setLineNum(lineNum);
        fieldCounter++;
        x--;
    }

    /**
     * The getImport method,processes the imports
     */       
    public void getImport(int i) 
    {
        Vector<String> importString = new Vector<String>();
        String temp = "";
        while(i < newlist.size())
        {
            if(newlist.get(i).getName().equals("import") || newlist.get(i).getName().equals("package"))
            {
                if(newlist.get(i).getName().equals("package"))
                {
                    temp = "";
                }
                else
                {
                    importString.add(temp);
                    temp = "";  
                }
            }
            else                
            {
                temp = newlist.get(i).getName() + temp;
            }
            i++;
        }
        
        for(int r = 0;r< importString.size() ;r++)
        {
            database.insertImport(className,importString.get(r));
        }
    }
    
    /**
     * The ConstructorMethod method,determenes if a method is a constructor and gets the line number of that constructor
     */   
    public void ConstructorMethod() 
    {
        String constructorName = className;
        int lineNum = newlist.get(x).getLineNum();
        boolean flag = true;
        while(flag == true)
        {
            if(newlist.get(x).getName().equals("VAR_DECLARATOR"))
            {
                innerVar();
            }
            if(newlist.get(x).getName().equals("FORMAL_PARAM_STD_DECL"))
            {
                parameter();
            }
            if(newlist.get(x).getName().equals("MODIFIER_LIST"))
            {
                flag = false;
            }
            x++;
        }
        declaration();
        int methodID = database.insertMethod(constructorName, "void", "constructor", className, methodFieldList,lineNum);
        int c = 0;
        while(c < fieldCounter)
        {
            int fieldID = database.insertField(parameterArray[c].getFieldName(), parameterArray[c].getAccmode(), parameterArray[c].getFieldType(), methodID+"", className, parameterArray[c].getArray(),"constructorParameter",parameterArray[c].getLineNum());
            c++;
            methodFieldList = methodFieldList + fieldID + " " ;
        }
        database.updatemethodFieldList(methodFieldList,methodID);
        methodFieldList = "";
        fieldCounter = 0;
        c = 0;
        while(c < innerCounter)
        {
            int fieldID = database.insertField(innervar[c].getFieldName(), innervar[c].getAccmode(), innervar[c].getFieldType(), methodID+"", className, innervar[c].getArray(),"constructorVariable",innervar[c].getLineNum());
            c++;
        }
        innerCounter = 0;
    }
}
